package com.tony.demo.ui.performance.xnyh.memory;

import android.util.SparseArray;

public abstract class ObjectPools<T> {
    private final Object lock = new Object();
    private SparseArray<T> freePool;  //对象池 存放空闲状态的对象
    private SparseArray<T> usingPool;  //正在使用中的对象
    private static final int DEFAULT_MAX_POOL_SIZE = 10;

    private int poolSize;
    private int maxPoolSize;

    public ObjectPools(int initCapacity, int maxPoolSize) {
        this.poolSize = initCapacity;
        this.maxPoolSize = maxPoolSize > poolSize ? maxPoolSize : poolSize;
        initPool();
    }

    public ObjectPools(int initCapacity) {
        this(initCapacity, DEFAULT_MAX_POOL_SIZE);
    }

    private void initPool() {
        usingPool = new SparseArray<>();
        freePool = new SparseArray<>(poolSize);
        for (int i = 0; i < poolSize; i++) {
            freePool.put(i, createObj());
//            if (i == 1) {
//                try {
//                    Field mSize = freePool.getClass().getDeclaredField("mSize");
//                    mSize.setAccessible(true);
//                    int size = (int) mSize.get(freePool);
//                    System.out.println("DMLog*******  mSize is " + size);
//                } catch (Exception e) {
//                    e.printStackTrace();
//                }
//            }
        }
    }

    /**
     * 由子类来实现
     */
    protected abstract T createObj();

    /**
     * 申请对象
     *
     * @return 返回对象池中的对象，如果没有，则创建新的对象；
     * 如果对象池和使用中的对象总数等于最大对象数后，就抛出异常
     */
    public T requestObj() {
        synchronized (lock) { //这里用freePool的话，AS提示  synchronization on a non-final field "freePool"
            T t;
            int size = freePool.size();
            for (int i = 0; i < size; i++) {
                int key = freePool.keyAt(i);
                t = freePool.get(key);
                if (null != t) {
                    freePool.remove(key);
                    usingPool.put(key, t);
                    return t;
                }
            }

            if (size + usingPool.size() < maxPoolSize) {
                if (size + usingPool.size() == maxPoolSize) {
                    throw new IndexOutOfBoundsException("the total pool size must less than maxPoolSize");
                }
                System.out.println("DMLog*******  create a new object, put to freePool");
                t = createObj();
                usingPool.put(size + usingPool.size(), t);
                return t;
            }
        }
        return null;
    }

    /**
     * 释放对象
     */
    public boolean release(T obj) {
        synchronized (lock) {
            if (null == obj) {
                return false;
            }

            int index = usingPool.indexOfValue(obj);
            if (index < 0) {
                return false;
            }

            int key = usingPool.keyAt(index);
            System.out.println("DMLog******* index = " + index + "\t key = " + key);
            freePool.put(key, obj);
            usingPool.remove(key);

//        onReleaseObj(obj);  //释放前，可以把这个对象交给用户处理
            return true;
        }
    }

    /**
     * 销毁对象池
     */
    public void destroyPool() {
        if (null != freePool) {
            freePool = null;
        }
        if (null != usingPool) {
            usingPool = null;
        }
    }
}
